package club.jdiy.core.base.domain;

import club.jdiy.core.ex.JDiyException;
import club.jdiy.core.ex.JDiyFormException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializable;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.ui.ModelMap;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Serializable;

/**
 * API JSON返回数据体封装
 *
 * @param <T> 返回数据体
 * @author ziquee(子秋) QQ号:39886616 主页: http://www.jdiy.club
 * @version 20200520
 */
@Getter
@NoArgsConstructor
public class Ret<T> implements Serializable {
    private int code;
    private T data;
    private String msg;

    public Ret(int code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public static <T> Ret<T> success() {
        return new Ret<>(RetCode.success.code, RetCode.success.msg, null);
    }

    public static <T> Ret<T> success(T data) {
        return new Ret<>(RetCode.success.code, RetCode.success.msg, data);
    }

    public static <T> Ret<T> success(T data, String msg) {
        return new Ret<>(RetCode.success.code, msg, data);
    }

    public static Ret<Object> successJson(String jsonString) {
        Ret<Object> ret = new Ret<>(RetCode.success.code, RetCode.success.msg, null);
        ret.data = new JsonSerializable() {
            @Override
            public void serialize(JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                jsonGenerator.writeRawValue(jsonString);
            }

            @Override
            public void serializeWithType(JsonGenerator jsonGenerator, SerializerProvider serializerProvider, TypeSerializer typeSerializer) {
            }
        };
        return ret;
    }

    public static <T> Ret<T> fail(String msg) {
        return new Ret<>(RetCode.fail.code, msg, null);
    }

    public static <T> Ret<T> fail(int code, String msg) {
        return new Ret<>(code, msg, null);
    }

    public static <T> Ret<T> error(Throwable t) {
        if (t instanceof JDiyFormException) {
            Ret1<T> r = new Ret1<>(RetCode.form_valid.getCode(), t.getMessage(), null);
            r.inputId = ((JDiyFormException) t).getInputId();
            return r;
        }
        if (!(t instanceof JDiyException)) t.printStackTrace();
        return new Ret<>(RetCode.fail.code, t.getMessage(), null);
    }

    @Deprecated
    public static String simple(ModelMap map, Type type, String msg) {
        map.put(type.name(), msg);
        return "common/simpleResult.ftl";
    }

    public static <T> T direct(HttpServletResponse response, Type type, String data) {
        try {
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-Type", "text/html; charset=utf-8");
            response.setContentType("text/html; charset=utf-8");
            PrintWriter out = response.getWriter();
            switch (type) {
                case msg:
                    out.print(data);//注意不要ln
                    break;
                case url:
                    out.println("<script type=\"text/javascript\">document.location.href = \"" + data + "\";</script>");
                    break;
                case script:
                    out.println("<script type=\"text/javascript\">" + data + "</script>");
                    break;
                case img:
                    out.println("<img src=\"" + data + "\"/>");
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public enum Type {
        msg,
        url,
        img,
        script,
    }

    public enum RetCode {
        success(200, "操作成功"),
        fail(502, "操作失败"),
        not_allowed(401, "不允许此操作"),
        unauthorized(403, "异地登录或超时退出"),
        not_found(404, "目标数据不存在"),
        invalid_param(202, "请求参数错误"),
        form_valid(203, "表单输入错误");
        private final String msg;
        private final int code;

        RetCode(int code, String desc) {
            this.code = code;
            this.msg = desc;
        }

        public String getMsg() {
            return msg;
        }

        public Integer getCode() {
            return code;
        }

    }
}
